package org.springframework.context.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.event.ApplicationEventMulticaster;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.context.event.SimpleApplicationEventMulticaster;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.io.DefaultResourceLoader;

import java.util.Collection;
import java.util.Map;

/**
 * 抽象应用上下文
 *
 * @author derekyi
 * @date 2020/11/28
 */
public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext {

	public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";

	public static final String CONVERSION_SERVICE_BEAN_NAME = "conversionService";

	private ApplicationEventMulticaster applicationEventMulticaster;

	@Override
	public void refresh() throws BeansException {
		//做了三件事情
		//1.创建BeanFactory（IOC容器）
		//2.并读取配置文件里的资源，创建BeanDefinition（属性填充好了）。
		//3.并且将BeanDefinition都注册进入map集合了
		refreshBeanFactory();

		//上面的方法，定义出来的ioc容器在这个类的内部，通过getBeanFactory直接取过来，
		//ConfigurableListableBeanFactory是ioc容器的接口，得到BeanFactory对象（IOC容器对象）
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();

		//这一步你可能觉得有点怪，为什么BeanPostProcessor对象的添加在这里，其实就是Aware接口添加（高级）IOC容器。直接在这一步添加了。
		//bean生命周期里，高级ioc的aware在前置方法里，实际上是在这里
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

		//1.创建了所有BeanFactoryPostProcessor对象，执行
		//2.依次执行了bean对象的方法，对beandefination修改（这俩方法只有这个区别！）。（上面的创建对象后存入map，直接下面执行方法）
		invokeBeanFactoryPostProcessors(beanFactory);
		//1.创建了所有BeanPostProcessor对象，注册
		//2.依次存入ioc容器的list集合，之后其他所有bean创建都会调用这些bean的方法（下面的创建对象后存入map，下面存入ioc容器的集合，不执行）
		registerBeanPostProcessors(beanFactory);

		//初始化事件发布者，存入ioc容器一级缓存。就是初始化ApplicationEventMulticaster事件管理者
		//1.创建一个ApplicationEventMulticaster实现类，并把ioc容器当作参数传入
		//2.把ApplicationEventMulticaster实现类以单例bean存入一级缓存（map）
		initApplicationEventMulticaster();

		//注册事件监听器，就是把xml文件的一个个事件监听器存入ioc容器指定位置
		//1.和前后置里一个方法一样，类型判断得到所有的事件监听器对象。存入事件发布者（总管）内部list集合
		registerListeners();

		//注册类型转换器（之后讲）和提前实例化单例bean（文档重点介绍）
		//ApplicationContext和基本的ioc容器有一个区别，
		//1.就是ApplicationContext会自动帮我们初始化化单例的bean！！！
		//2.有类型转换器
		finishBeanFactoryInitialization(beanFactory);

		//发布容器刷新完成事件，涉及到事件操作
		//1.创建（容器刷新事件类）的对象，容器是ioc容器本身。
		//2.内部通过事件发布者，发布一个事件，
		// 判断是否有符合的事件监听器。有就执行一次（这是第一次）
		finishRefresh();
	}

	protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {



		//设置类型转换器
		//询问ioc容器是否包含当前conversionService这个bean的beandefinition对象（map里找）
		if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {

			//如果有，就创建这个bean对象（除了前后置类，beandefinition操作类，单例类，在单例类bean创建前
			// 会先创建类转换器的bean实例）
			Object conversionService = beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME);

			if (conversionService instanceof ConversionService) {
				beanFactory.setConversionService((ConversionService) conversionService);
			}
		}


		//提前实例化单例bean（进入查看）
		beanFactory.preInstantiateSingletons();
	}

	/**
	 * 创建BeanFactory，并加载BeanDefinition
	 *
	 * @throws BeansException
	 */
	protected abstract void refreshBeanFactory() throws BeansException;




	/**
	 * 在bean实例化之前，执行BeanFactoryPostProcessor
	 *
	 * @param beanFactory
	 */
	//我们看看他是如何执行的
	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		//首先你肯定要获得BeanFactoryPostProcessor类
		//getBeansOfType方法，是匹配方法，BeanFactoryPostProcessor是接口，继承了这个接口的类会匹配
		Map<String, BeanFactoryPostProcessor> beanFactoryPostProcessorMap =
				beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);

		//这里是对bean做一个类型判断，所有实现了BeanFactoryPostProcessor这个接口的类，都会被存入一个map集合
		//beanFactoryPostProcessorMap对象就是这个map集合


		//返回了所有我们定义的BeanFactoryPostProcessor类的子类，存入map集合
		//然后开始循环，做beanFactoryPostProcessor里的方法
		for (BeanFactoryPostProcessor beanFactoryPostProcessor : beanFactoryPostProcessorMap.values()) {
			//ioc容器也交给他，beanFactoryPostProcessor是一个继承了beanFactoryPostProcessor的bean的实例
			beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
			//这里执行bean实例里重写的方法postProcessBeanFactory
		}



	}

	/**
	 * 注册BeanPostProcessor
	 *
	 * @param beanFactory
	 */
	protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		Map<String, BeanPostProcessor> beanPostProcessorMap =
				beanFactory.getBeansOfType(BeanPostProcessor.class);
		//逻辑和上面哪个工厂的一样，添加进入map
		for (BeanPostProcessor beanPostProcessor : beanPostProcessorMap.values()) {
			beanFactory.addBeanPostProcessor(beanPostProcessor);
		}
	}

	/**
	 * 初始化事件发布者
	 */
	protected void initApplicationEventMulticaster() {
		//先获取ioc容器beanFactory
		ConfigurableListableBeanFactory beanFactory = getBeanFactory();
		//传入ioc容器，创建applicationEventMulticaster的一个实现类（事件发布者）
		applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);

		//applicationEventMulticaster这个实例bean，被存入了ioc容器！而且是用单例bean的方式
		//直接调用了ioc容器的添加单例bean方式，将总管存入进去。一级缓存map里
		beanFactory.addSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
	}

	/**
	 * 注册事件监听器
	 */
	protected void registerListeners() {
		//这个方法我们见过很多次了，类型判断ApplicationListener接口的实现类。
		//也就是创建出事件监听器的bean对象了。存入集合
		Collection<ApplicationListener> applicationListeners =
				getBeansOfType(ApplicationListener.class).values();
		for (ApplicationListener applicationListener : applicationListeners) {

			//得到三个事件监听器。依次存入事件发布者
			//调用者是applicationEventMulticaster（事件发布者），在头上的方法里
			applicationEventMulticaster.addApplicationListener(applicationListener);
		}
	}

	/**
	 * 发布容器刷新完成事件
	 */
	//这个publishEvent方法也是application（ioc高级容器）内部的方法。（注意为什么强调application内部的方法，原因如下）
	protected void finishRefresh() {
		//这是一个发布事件的方法，里面的参数是需要发布事件的事件对象本身

		//new ContextRefreshedEvent，是一个事件的对象。ioc容器刷新完成的事件对象
		publishEvent(new ContextRefreshedEvent(this));

		//publishEvent可以发布事件，这是事件发布者做的事情，我们看里面果然是事件发布者
		//我们这里new ContextRefreshedEvent（也就是刷新事件，而这个刷新的目标是this，也就是ioc容器本身）

	}

	@Override
	public void publishEvent(ApplicationEvent event) {
		//果然是总管的方法，我说谁能发布事物，肯定是事物发布者
		//applicationEventMulticaster的multicastEvent方法，对外发布时间
		applicationEventMulticaster.multicastEvent(event);
	}

	@Override
	public boolean containsBean(String name) {
		return getBeanFactory().containsBean(name);
	}

	@Override
	public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
		return getBeanFactory().getBean(name, requiredType);
	}

	@Override
	public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
		return getBeanFactory().getBeansOfType(type);
	}

	public <T> T getBean(Class<T> requiredType) throws BeansException {
		return getBeanFactory().getBean(requiredType);
	}

	@Override
	public Object getBean(String name) throws BeansException {
		return getBeanFactory().getBean(name);
	}

	public String[] getBeanDefinitionNames() {
		return getBeanFactory().getBeanDefinitionNames();
	}

	public abstract ConfigurableListableBeanFactory getBeanFactory();

	public void close() {
		doClose();
	}

	public void registerShutdownHook() {
		Thread shutdownHook = new Thread() {
			public void run() {
				doClose();
			}
		};
		Runtime.getRuntime().addShutdownHook(shutdownHook);

	}

	protected void doClose() {
		//发布容器关闭事件
		publishEvent(new ContextClosedEvent(this));

		//执行单例bean的销毁方法
		destroyBeans();
	}

	protected void destroyBeans() {
		getBeanFactory().destroySingletons();
	}
}

